﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using Db4objects.Db4o.Collections;
using Db4objects.Db4o.Linq;
using Db4objects.Db4o.Reflect.Generic;
using ZOIL.DataBackend.Db4o.Properties;
using ZOIL.DataBackend.Server;
using ZOIL.DataModel;

namespace ZOIL.DataBackend.Db4o
{
    [Export(typeof(CollectionConnectionBase))]
    public class Db4oCollectionConnection : CollectionConnectionBase
    {
        #region private

        private DatabaseConfiguration _databaseConfiguration;

        private bool _isLocalServerRunning = false;

        #endregion

        public Db4oCollectionConnection()
        {
            Host = "localhost";
            Port = 4488;
            Username = "admin";
            Password = "admin";
            CommitInterval = null;
        }

        private string Host { get; set; }
        private Db4oCollectionConnection UseHost(string host)
        {
            Host = host;
            return this;
        }

        private int Port { get; set; }
        private Db4oCollectionConnection UsePort(int port)
        {
            Port = port;
            return this;
        }

        private string Username { get; set; }
        private Db4oCollectionConnection UseUsername(string username)
        {
            Username = username;
            return this;
        }

        private string Password { get; set; }
        private Db4oCollectionConnection UsePassword(string password)
        {
            Password = password;
            return this;
        }

        private TimeSpan? CommitInterval { get; set; }
        private Db4oCollectionConnection UseCommitInterval(TimeSpan? commitInterval)
        {
            CommitInterval = commitInterval;
            return this;
        }

        #region Implementation of IConnection

        public override string FriendlyName
        {
            get { return "Db4o Database"; }
        }

        public override Bitmap Icon
        {
            get { return Resources.Db4oLogo; }
        }

        public override IPersistableCollection Connect(Dictionary<string, object> parameters)
        {
            UseHost((string)parameters["host"]);
            UsePort((int)parameters["port"]);
            UseUsername((string)parameters["username"]);
            UsePassword((string)parameters["password"]);
            UseCommitInterval((TimeSpan)parameters["useCommitInterval"]);

            var db = Database.Instance;
            db.Configure(Host, Port, Username, Password, true);
            if (CommitInterval.HasValue)
            {
                db.CommitInterval = CommitInterval.Value.TotalMilliseconds;
            }

            var coll2 = (from GenericObject c in db.Objects select c).SingleOrDefault();

            //erst versuchen existierende Collection zu holen
            var coll = (from Db4oCollection c in db.Objects select c).SingleOrDefault();
            if (coll == null)
            {
                //sonst neue erstellen
                coll = new Db4oCollection();
                db.StoreAndCommit(coll);
            }
            else
            {
                coll.OnCreated();
            }
            return coll;
        }

        public override IList<T> CreateList<T>()
        {
            return new ArrayList4<T>();
        }

        public override ObservableCollection<T> CreateObservableCollection<T>()
        {
            return new ObservableCollection4<T>();
        }

        public override bool CanStartLocalDatabase()
        {
            return true;
        }

        public override void StartLocalDatabase(Dictionary<string, object> parameters)
        {
            #region Prepare database path

            var commonApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            var databasePath = Path.Combine(commonApplicationData, "HCI Group", "ZOIL", "Database");

            if (!Directory.Exists(databasePath))
                Directory.CreateDirectory(databasePath);

            Server.Server.getInstance().DatabaseDirectory = databasePath;

            #endregion

            var databaseName = (string)parameters["databaseName"];
            var port = (int)parameters["port"];
            var username = (string)parameters["username"];
            var password = (string)parameters["password"];

            //var server = Server.Instance();

            _databaseConfiguration = new DatabaseConfiguration
            {
                DatabaseFile = databaseName,
                Port = port,
                UseMemoryIOAdapter = true
            };
            _databaseConfiguration.Users.Add(new DatabaseUser(username, password));

            _databaseConfiguration.Server.Start(_databaseConfiguration);

            _isLocalServerRunning = true;

            // provide some time to startup database
            Thread.Sleep(2000);
        }

        public override void Dispose()
        {
            Database.Instance.Close();

            if (_isLocalServerRunning)
                _databaseConfiguration.Server.Stop();
        }

        #endregion
    }
}